﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using WoChu.Infrastructure.Log;
using WoChu.Infrastructure.Net;
using WoChu.Infrastructure.Web;

namespace WoChu.Infrastructure.Video
{
    /// <summary>
    /// 视频播放的SDK接口
    /// </summary>
    public class VideoHelper
    {
        Int32 m_lUserID = -1;    //用户编号
        public CHCNetSDK.NET_DVR_DEVICEINFO_V30 DeviceInfo;  //通道
        public CHCNetSDK.NET_DVR_IPPARACFG_V40 m_struIpParaCfgV40;
        [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 96, ArraySubType = UnmanagedType.U4)]
        public int[] iChannelNum = new int[96];      //通道号 
        int m_lDownHandle = -1;
        ILog _log;
        string _vedioPath;
        public VideoHelper(bool isSdkLog = true,ILog log=null)
        {
            bool m_bInitSDK = CHCNetSDK.NET_DVR_Init();
            if (m_bInitSDK == false)
            {
                _log.LogError("报错", "CHCNetSDK.NET_DVR_Init() 执行报错");
                throw new Exception("初始化报错!");
            }
            if (isSdkLog)//启用SDK日志
            {
                CHCNetSDK.NET_DVR_SetLogToFile(3, "C:\\SdkLog\\", true);
            }
            _log = log;
        }

        /// <summary>
        ///  登录，默认portNumber：8000 
        /// </summary>
        /// <param name="iPAddress"></param>        
        /// <returns></returns>
        public int LoginWithConfig(string ipAddress)
        {
            var userName = ConfigSetting.GetConfigValueByName<string>("Video.UserName");
            var password = ConfigSetting.GetConfigValueByName<string>("Video.Password");
            var portNumber = ConfigSetting.GetConfigValueByName<short>("Video.PortNumber");
            return Login(ipAddress, portNumber, userName, password);
        }

        /// <summary>
        ///  登录，默认portNumber：8000 
        /// </summary>
        /// <param name="iPAddress"></param>
        /// <param name="portNumber"></param>
        /// <param name="userName"></param>
        /// <param name="password"></param>
        /// <returns></returns>
        public int Login(string iPAddress, Int16 portNumber=8000, string userName="admin", string password="")
        {
            m_lUserID = CHCNetSDK.NET_DVR_Login_V30(iPAddress, portNumber, userName, password, ref DeviceInfo);
            if (m_lUserID < 0)
                throw new Exception(GetLastError());
            _log.LogInfo("登录成功", string.Format("ip:{0}",iPAddress));
            LoadChannel();
            return m_lUserID;
        }

        public void Logout()
        {
            if (m_lUserID < 0)
                return;
            //注销登录 Logout the device
            if (!CHCNetSDK.NET_DVR_Logout(m_lUserID))
            {
                throw new Exception(GetLastError());
            }
            m_lUserID = -1;
        }

        public void LoadChannel()
        {
            uint dwAChanTotalNum = (uint)DeviceInfo.byChanNum;
            uint dwDChanTotalNum = (uint)DeviceInfo.byIPChanNum + 256 * (uint)DeviceInfo.byHighDChanNum;

            if (dwDChanTotalNum > 0)
            {
                #region 加载
                //CHCNetSDK.NET_DVR_IPPARACFG_V40 m_struIpParaCfgV40;

                uint dwSize = (uint)Marshal.SizeOf(m_struIpParaCfgV40);

                IntPtr ptrIpParaCfgV40 = Marshal.AllocHGlobal((Int32)dwSize);
                Marshal.StructureToPtr(m_struIpParaCfgV40, ptrIpParaCfgV40, false);

                uint dwReturn = 0;
                int iGroupNo = 0; //该Demo仅获取第一组64个通道，如果设备IP通道大于64路，需要按组号0~i多次调用NET_DVR_GET_IPPARACFG_V40获取
                if (!CHCNetSDK.NET_DVR_GetDVRConfig(m_lUserID, CHCNetSDK.NET_DVR_GET_IPPARACFG_V40, iGroupNo, ptrIpParaCfgV40, dwSize, ref dwReturn))
                {
                    throw new Exception(GetLastError());
                }
                else
                {
                    // succ
                    m_struIpParaCfgV40 = (CHCNetSDK.NET_DVR_IPPARACFG_V40)Marshal.PtrToStructure(ptrIpParaCfgV40, typeof(CHCNetSDK.NET_DVR_IPPARACFG_V40));

                    for (int i = 0; i < dwAChanTotalNum; i++)
                    {
                        iChannelNum[i] = i + (int)DeviceInfo.byStartChan;
                    }
                    byte byStreamType;
                    uint iDChanNum = 64;

                    if (dwDChanTotalNum < 64)
                    {
                        iDChanNum = dwDChanTotalNum; //如果设备IP通道小于64路，按实际路数获取
                    }
                    for (int i = 0; i < iDChanNum; i++)
                    {
                        iChannelNum[i + dwAChanTotalNum] = i + (int)m_struIpParaCfgV40.dwStartDChan;
                    }
                }
                Marshal.FreeHGlobal(ptrIpParaCfgV40);
                #endregion
            }
            else
            {
                for (int i = 0; i < dwAChanTotalNum; i++)
                {
                    // ListAnalogChannel(i + 1, 1);
                    iChannelNum[i] = i + (int)DeviceInfo.byStartChan;
                }
                // MessageBox.Show("Th  is device has no IP channel!");
            }
        }

        public void DownLoadVideoFile(DateTime startDate, DateTime endDate, int channelIndex, string vedioPath = "")
        {
            if (startDate >= endDate)
                throw new Exception(string.Format("开始必须>结束时间 {0} {1}", startDate, endDate));
            if (string.IsNullOrEmpty(vedioPath))
            {
                vedioPath = "D:\\";
            }
            var dirPath = Path.GetDirectoryName(vedioPath);
            DirectoryHelper.CreateNoExist(dirPath);
            _vedioPath = vedioPath;
            CHCNetSDK.NET_DVR_PLAYCOND struDownPara = new CHCNetSDK.NET_DVR_PLAYCOND();
            struDownPara.dwChannel = (uint)iChannelNum[channelIndex - 1]; //通道号 Channel number  
            struDownPara.struStartTime = ConvertDVRTime(startDate);
            struDownPara.struStopTime = ConvertDVRTime(endDate);
            //按时间下载 Download by time
            m_lDownHandle = CHCNetSDK.NET_DVR_GetFileByTime_V40(m_lUserID, vedioPath, ref struDownPara);
            if (m_lDownHandle < 0)
            {
                throw new Exception(GetLastError());
            }

            uint iOutValue = 0;
            if (!CHCNetSDK.NET_DVR_PlayBackControl_V40(m_lDownHandle, CHCNetSDK.NET_DVR_PLAYSTART, IntPtr.Zero, 0, IntPtr.Zero, ref iOutValue))
            {
                throw new Exception(GetLastError());
            }
            _log.LogInfo("开始下载视频", string.Format("文件名:{0}",vedioPath));
        }

        /// <summary>
        /// 下载进度，若是 0-100 之间是正常 
        /// 100是完成 ，若200，则抛异常 ，若-1代表没有下载任务
        /// </summary>
        /// <returns></returns>
        public int GetDownloadPosition()
        {
            if (m_lDownHandle < 0)
                return -1;
            int iPos = CHCNetSDK.NET_DVR_GetDownloadPos(m_lDownHandle);
            if (iPos == 100)  //下载完成
                _log.LogInfo("下载完成", string.Format("文件名:{0}", _vedioPath));
            else
                _log.LogInfo("正在下载", string.Format("文件名:{0} 进度：{1}", _vedioPath,iPos));
            return iPos;
        }

        public void StopDownload()
        {
            if (m_lDownHandle < 0)
                return;
            //停止下载 Stop download
            CHCNetSDK.NET_DVR_StopGetFile(m_lDownHandle);
            m_lDownHandle = -1;
        }

        public List<VideoFlieInfo> GetVideoFiles(DateTime startDate, DateTime endDate, int channelIndex)
        {
            if (channelIndex < 0 || iChannelNum.Count() > channelIndex)
                throw new Exception(string.Format("channelIndex值超出范围 channelIndex：{0}", channelIndex));

            CHCNetSDK.NET_DVR_FILECOND_V40 struFileCond_V40 = new CHCNetSDK.NET_DVR_FILECOND_V40();
            struFileCond_V40.lChannel = iChannelNum[channelIndex - 1]; //通道号 Channel number
            struFileCond_V40.dwFileType = 0xff; //0xff-全部，0-定时录像，1-移动侦测，2-报警触发，...
            struFileCond_V40.dwIsLocked = 0xff; //0-未锁定文件，1-锁定文件，0xff表示所有文件（包括锁定和未锁定）
            struFileCond_V40.struStartTime = ConvertDVRTime(startDate);
            struFileCond_V40.struStartTime = ConvertDVRTime(endDate);
            //开始录像文件查找 Start to search video files 
            int m_lFindHandle = CHCNetSDK.NET_DVR_FindFile_V40(m_lUserID, ref struFileCond_V40);
            if (m_lFindHandle < 0)
            {
                throw new Exception(GetLastError());
            }
            CHCNetSDK.NET_DVR_FINDDATA_V30 struFileData = new CHCNetSDK.NET_DVR_FINDDATA_V30();
            List<VideoFlieInfo> vedioList = new List<VideoFlieInfo>();
            while (true)
            {
                //逐个获取查找到的文件信息 Get file information one by one.
                int result = CHCNetSDK.NET_DVR_FindNextFile_V30(m_lFindHandle, ref struFileData);

                if (result == CHCNetSDK.NET_DVR_ISFINDING)  //正在查找请等待 Searching, please wait
                {
                    continue;
                }
                else if (result == CHCNetSDK.NET_DVR_FILE_SUCCESS) //获取文件信息成功 Get the file information successfully
                {
                    vedioList.Add(new VideoFlieInfo() { FileName = struFileData.sFileName, StartDate = ConvertDateTime(struFileData.struStartTime), EndDate = ConvertDateTime(struFileData.struStopTime) });
                }
                else if (result == CHCNetSDK.NET_DVR_FILE_NOFIND || result == CHCNetSDK.NET_DVR_NOMOREFILE)
                {
                    break; //未查找到文件或者查找结束，退出   No file found or no more file found, search is finished 
                }
                else
                {
                    break;
                }
            }
            return vedioList;
        }

        public string GetLastError()
        {
            uint errorCode = CHCNetSDK.NET_DVR_GetLastError();
            string msg = string.Format("错误编号:{0}", errorCode);
            _log.LogError("错误",msg);
            return msg;
        }

        CHCNetSDK.NET_DVR_TIME ConvertDVRTime(DateTime dt)
        {
            CHCNetSDK.NET_DVR_TIME dvrTime = new CHCNetSDK.NET_DVR_TIME();
            dvrTime.dwYear = (uint)dt.Year;
            dvrTime.dwMonth = (uint)dt.Month;
            dvrTime.dwDay = (uint)dt.Day;
            dvrTime.dwHour = (uint)dt.Hour;
            dvrTime.dwMinute = (uint)dt.Minute;
            dvrTime.dwSecond = (uint)dt.Second;
            return dvrTime;
        }

        DateTime ConvertDateTime(CHCNetSDK.NET_DVR_TIME dvrTime)
        {
            DateTime dt = new DateTime((int)dvrTime.dwYear, (int)dvrTime.dwMonth, (int)dvrTime.dwDay, (int)dvrTime.dwHour, (int)dvrTime.dwMinute, (int)dvrTime.dwSecond);
            return dt;
        }
    }

    public class VideoServer
    {
        public string Ip { get; set; }

        public int ChannelIndex { get; set; }

        public object Parms { get; set; }
    }

    /// <summary>
    /// 视频对象
    /// </summary>
    public class VideoFlieInfo
    {
        public string FileName { get; set; }

        public DateTime StartDate { get; set; }
        public DateTime EndDate { get; set; }
    }
}
